#include "io.h"

/////////////////////////////////////////////////////////////////////////////
//版本信息
#define VERSION_MAJOR                   	0
#define VERSION_MINOR                   	1

/////////////////////////////////////////////////////////////////////////////
// 1，站号：1-网口一排 和 2 - 扩展板  DO(闭合:0 断开:1) DI(24V接入:1 24V未接:0)
// 2，8路DI对应地址：00 ~ 08
// 3，6路DO对应地址：00 ~ 06
// 通过Mobdus TCP Modbus地址:1 离散寄存器地址: DI:100~115   DOStae 116~ 127  
//                             保持寄存器地址: DOCtrl:100~111
// 通过Redis交互约定：       DI:Bams_DI1 Bams_DI16
//                           DO:Bams_DO1 Bams_DO12

/////////////////////////////////////////////////////////////////////////////
// 更新记录
// 0.1 - 

CIO::CIO(QObject *parent)
    : QThread(parent)
{
    m_pSerial = new CXnSerial;

    //m_pRTDB = 0;
    m_pIOModule = 0;

    m_bSerialOK = false;
#ifdef XNWIN
    m_strPortName = "com4";         // 串口名
#else
    m_strPortName = "/dev/ttyS5";   // 串口名
    //m_strPortName = "/dev/ttyS8";   // 串口名
#endif 
    m_iBaudRate = 115200;     // 波特率
    m_iDataBits = 8;          // 数据位
    m_iStopBits = 1;          // 停止位
    m_iParity = 0;            // 校验位
    m_iRtscts = 0;

#if XNWIN
    m_bPrintMsg = true;
#else
    m_bPrintMsg = true;
#endif

    m_iSerialDataLen = 0;
    m_logCount = 0;
    m_pSerialDataBuf = new char[DATA_BUFFER_LENGHT];  // data buffer

    printf("XnIO Version %d.%d RTDB %d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, BAMS_VERSION_MAJOR, BAMS_VERSION_MINOR, BAMS_VERSION_REVISION);
}

CIO::~CIO()
{
    if (m_pSerial)
    {
        delete m_pSerial;
        m_pSerial = 0;
    }

    if (m_pSerialDataBuf)
    {
        delete[] m_pSerialDataBuf;
        m_pSerialDataBuf = 0;
    }
}

int CIO::init()
{
    // some variables
    int iRetVal = -999;

    /*
	// Init RTDB
	m_pRTDB = new CRTDB(1, 1, MAX_BANK_NUM, 10, 10, 10, 10, 10);
	if (!m_pRTDB || m_pRTDB->initRTDB(true) < 0)
	{
		iRetVal = -1;
	}
	else
	{
		m_pIOModule = m_pRTDB->getIOModule();
		if (m_pIOModule)
		{
			iRetVal = 0;
		}
	}*/
    m_pIOModule = ::getIOModule();
    iRetVal = 0;

    return iRetVal;
}

//CIOModule* CIO::getIOModule()
//{
//	return m_pIOModule;
//}

void CIO::printSendInfo(char* pDataBuf, int iLen)
{
    if (m_bPrintMsg)
    {
        if (m_logCount > 50)
            return;
        m_logCount += 1;

        QString strPrintInfo = "";
        QChar aFillChar = '0';

        for (int i = 0; i < iLen; ++i)
        {
            strPrintInfo += QString("%1 ").arg((uchar)*(pDataBuf + i), 2, 16, aFillChar);
        }

        strPrintInfo = strPrintInfo.toUpper();

        strPrintInfo = "Send Datagram:" + strPrintInfo + "\n";

        printf(strPrintInfo.toLatin1().data());
    }
}

void CIO::printReceInfo(char* pDataBuf, int iLen)
{
    if (m_bPrintMsg)
    {
        if (m_logCount > 50)
            return;

        QString strPrintInfo = "";
        QChar aFillChar = '0';

        for (int i = 0; i < iLen; ++i)
        {
            strPrintInfo += QString("%1 ").arg((uchar)*(pDataBuf + i), 2, 16, aFillChar);
        }

        strPrintInfo = strPrintInfo.toUpper();

        strPrintInfo = "Rece Datagram:" + strPrintInfo + "\n";

        printf(strPrintInfo.toLatin1().data());
    }
}

// Read DI type = 1   0x02
// Write DO type = 2  0x05
// Read DO type = 3   0x01
int CIO::formDatagram(int iType, int iModbusID, int iDOIndex, quint16 usDOCtrlVal)
{
    int iLen = 0;
    quint16 usTemp = 0;
    if (1 == iModbusID || 2 == iModbusID)
    {
        if (1 == iType)       // Read DI type = 1   0x02
        {
            iLen = 0;
            memset(m_pSerialDataBuf, 0, DATA_BUFFER_LENGHT);

            *(m_pSerialDataBuf + iLen) = (char)iModbusID;
            iLen += 1;

            *(m_pSerialDataBuf + iLen) = 0x02;
            iLen += 1;

            usTemp = 0x0000;
            addParam2Buffer(m_pSerialDataBuf + iLen, usTemp);
            iLen += 2;

            usTemp = 8;
            addParam2Buffer(m_pSerialDataBuf + iLen, usTemp);
            iLen += 2;

            addModbusCRC2Buffer(m_pSerialDataBuf, iLen);
            iLen += 2;
        }
        else if (2 == iType)  // Write DO type = 2  0x05
        {
            iLen = 0;
            memset(m_pSerialDataBuf, 0, DATA_BUFFER_LENGHT);

            *(m_pSerialDataBuf + iLen) = (char)iModbusID;
            iLen += 1;

            *(m_pSerialDataBuf + iLen) = 0x05;
            iLen += 1;

            usTemp = (quint16)(iDOIndex);
            addParam2Buffer(m_pSerialDataBuf + iLen, usTemp);
            iLen += 2;

            if (usDOCtrlVal > 0)
            {
                usTemp = 0xFF00;
            }
            else
            {
                usTemp = 0x0000;
            }
            addParam2Buffer(m_pSerialDataBuf + iLen, usTemp);
            iLen += 2;

            addModbusCRC2Buffer(m_pSerialDataBuf, iLen);
            iLen += 2;
        }
        else if (3 == iType)  // Read DO type = 3   0x01
        {
            iLen = 0;
            memset(m_pSerialDataBuf, 0, DATA_BUFFER_LENGHT);

            *(m_pSerialDataBuf + iLen) = (char)iModbusID;
            iLen += 1;

            *(m_pSerialDataBuf + iLen) = 0x01;
            iLen += 1;

            usTemp = 0x00;
            addParam2Buffer(m_pSerialDataBuf + iLen, usTemp);
            iLen += 2;

            usTemp = 6;
            addParam2Buffer(m_pSerialDataBuf + iLen, usTemp);
            iLen += 2;

            addModbusCRC2Buffer(m_pSerialDataBuf, iLen);
            iLen += 2;
        }
        else
        {
            iLen = -2;
        }
    }
    else
    {
        iLen = -1;
    }

    return iLen;
}

int g_readDiCount = 0;
int CIO::analyDatagram(int iType, int iModbusID, char* pDataBuf, int iLen)
{
    // some varibales
    int iIndex = 0;
    int iIndex1 = 0;
    uchar uaModbusAddr = 0;
    uchar uaFuncCode = 0;
    uchar uaByteNum = 0;
    uchar uaData= 0;
    quint16 usTemp16 = 0;

    if (0 == pDataBuf || iLen < 6)
    {
        return -1;
    }

    // 校验报文是否正确
    iIndex = 0;

    uaModbusAddr = *(uchar*)pDataBuf;
    ++iIndex;

    uaFuncCode = *(uchar*)(pDataBuf + iIndex);
    ++iIndex;

    // get CRC
    getParamFromBuffer(pDataBuf + iLen - 2, usTemp16);

    if (usTemp16 != Modbus_CRC16(pDataBuf, iLen - 2))
    {
        return -2;
    }

    if (iModbusID != uaModbusAddr)
    {
        return -3;
    }

    if (1 == iType) // Read DI type = 1   0x02
    {
        if (0x02 != uaFuncCode)
        {
            return -4;
        }
    }
    else if (2 == iType) // Write DO type = 2  0x05
    {
        if (0x05 != uaFuncCode)
        {
            return -4;
        }
    }
    else if (3 == iType)  // Read DO type = 3   0x01
    {
        if (0x01 != uaFuncCode)
        {
            return -4;
        }
    }
    else
    {
        return -4;
    }

    // 数据解析
    if (1 == iType) // Read DI type = 1   0x02
    {
        uaByteNum = *(uchar*)(pDataBuf + iIndex);
        ++iIndex;
        uaData = *(uchar*)(pDataBuf + iIndex);
        ++iIndex;

        for (iIndex1 = 0; iIndex1 < 8; ++iIndex1)
        {
            if ((iModbusID - 1) * 8 + iIndex1 < 16)
            {
                if ((uaData & 0x01) > 0)
                {
                    m_pIOModule->usDI[(iModbusID -1) * 8 + iIndex1] = 1;
                }
                else
                {
                    m_pIOModule->usDI[(iModbusID - 1) * 8 + iIndex1] = 0;
                }

                uaData = uaData >> 1;
            }
        }

        if (g_readDiCount < 10)
        {
            g_readDiCount += 1;
            printf("CIO read DI1-8:%d-%d-%d-%d-%d-%d-%d-%d, DI9-16:%d-%d-%d-%d-%d-%d-%d-%d\n",
                   m_pIOModule->usDI[0],m_pIOModule->usDI[1],m_pIOModule->usDI[2],m_pIOModule->usDI[3],
                   m_pIOModule->usDI[4],m_pIOModule->usDI[5],m_pIOModule->usDI[6],m_pIOModule->usDI[7],
                   m_pIOModule->usDI[8],m_pIOModule->usDI[9],m_pIOModule->usDI[10],m_pIOModule->usDI[11],
                   m_pIOModule->usDI[12],m_pIOModule->usDI[13],m_pIOModule->usDI[14],m_pIOModule->usDI[15]);
        }
        iIndex = 0;
    }
    else if (2 == iType) // Write DO type = 2  0x05
    {
        iIndex = 0;
    }
    else if (3 == iType)  // Read DO type = 3   0x01
    {
        uaByteNum = *(uchar*)(pDataBuf + iIndex);
        ++iIndex;
        uaData = *(uchar*)(pDataBuf + iIndex);
        ++iIndex;

        for (iIndex1 = 0; iIndex1 < 6; ++iIndex1)
        {
            if ((iModbusID - 1) * 6 + iIndex1 < 12)
            {
                if ((uaData & 0x01) > 0)
                {
                    m_pIOModule->usDOState[(iModbusID - 1) * 6 + iIndex1] = 1;
                }
                else
                {
                    m_pIOModule->usDOState[(iModbusID - 1) * 6 + iIndex1] = 0;
                }

                uaData = uaData >> 1;
            }
        }

        if (g_readDiCount < 10)
        {
            printf("CIO read DO1-8:%d-%d-%d-%d-%d-%d-%d-%d, DO9-12:%d-%d-%d-%d\n",
                   m_pIOModule->usDOState[0],m_pIOModule->usDOState[1],m_pIOModule->usDOState[2],m_pIOModule->usDOState[3],
                   m_pIOModule->usDOState[4],m_pIOModule->usDOState[5],m_pIOModule->usDOState[6],m_pIOModule->usDOState[7],
                   m_pIOModule->usDOState[8],m_pIOModule->usDOState[9],m_pIOModule->usDOState[10],m_pIOModule->usDOState[11]);
        }
        iIndex = 0;
    }
    else
    {
        return -4;
    }

    return iIndex;
}

void CIO::readDataFromSerial()
{
    int iTryReadLen = 0;
    int iTryReadNum = 0;

    memset(m_pSerialDataBuf, 0, SNED_BUFFER_LENGHT);
    m_iSerialDataLen = m_pSerial->readBlock((unsigned char *)m_pSerialDataBuf, SNED_BUFFER_LENGHT, 10); // 100ms

    if (m_iSerialDataLen > 0)
    {
        iTryReadLen = m_iSerialDataLen;
        iTryReadNum = 0;

        while (iTryReadLen > 0 && iTryReadNum < 1 && iTryReadLen < SNED_BUFFER_LENGHT)
        {
            iTryReadLen = m_pSerial->readBlock((unsigned char *)(m_pSerialDataBuf + m_iSerialDataLen), SNED_BUFFER_LENGHT - m_iSerialDataLen, 10);

            if (iTryReadLen > 0)
            {
                m_iSerialDataLen += iTryReadLen;

                if (m_iSerialDataLen >= SNED_BUFFER_LENGHT)
                {
                    break;
                }
            }

            ++iTryReadNum;
        }
    }
}


void CIO::run()
{
    sleep(1);

    // open serial
    int iSpeed = B9600;
    if (2400 == m_iBaudRate)
    {
        iSpeed = B2400;
    }
    else if (4800 == m_iBaudRate)
    {
        iSpeed = B4800;
    }
    else if (9600 == m_iBaudRate)
    {
        iSpeed = B9600;
    }
    else if (19200 == m_iBaudRate)
    {
        iSpeed = B19200;
    }
    else if (115200 == m_iBaudRate)
    {
        iSpeed = B115200;
    }
    else
    {
        iSpeed = B9600;
    }

    if (m_pSerial->openDevice(m_strPortName.toLatin1().data(), iSpeed, 1, m_iRtscts, m_iDataBits, m_iStopBits, m_iParity) >= 0)
    {
        m_bSerialOK = true;
        printf(QString("Open serial(%1) OK!\n").arg(m_strPortName).toLatin1().data());
    }
    else
    {
        printf(QString("Open serial(%1) FAILED!\n").arg(m_strPortName).toLatin1().data());
    }

    // Some Varaiables
    int iIndex = 0;
    int iIndexDO = 0;
    //int isFirstTimeRun = 1;
    int runCount = 0;

    while (m_bSerialOK)  // 10 circle per second
    {
        this->msleep(30);

        for (iIndex = 0; iIndex < 2; ++iIndex)
        {
            // Read DI type = 1
            m_iSerialDataLen = formDatagram(1, iIndex + 1);
            if (m_logCount <= 30)
            {
                printf("==================m_iSerialDataLen:%d\n", m_iSerialDataLen);
                m_logCount += 1;
            }

            if (m_iSerialDataLen >= 8)
            {
                printSendInfo(m_pSerialDataBuf, m_iSerialDataLen);
                if (m_iSerialDataLen == m_pSerial->writeBlock((unsigned char *)m_pSerialDataBuf, m_iSerialDataLen))
                {
                    // Read from serial
                    readDataFromSerial();
                    printReceInfo(m_pSerialDataBuf, m_iSerialDataLen);

                    if (m_iSerialDataLen >= 6) // read OK
                    {
                        int ret = analyDatagram(1, iIndex + 1, m_pSerialDataBuf, m_iSerialDataLen);
                        //printf("==================analyDatagram Read DI ret:%d\n", ret);

                    }
                }
            }

            // Write DO type = 2
            for (iIndexDO = 0; iIndexDO < 6; ++iIndexDO)
            {
                if (runCount >= 11 && iIndex * 6 + iIndexDO < 12)
                {
                    if (m_pIOModule->usDOState[iIndex * 6 + iIndexDO] != m_pIOModule->usDOCtrl[iIndex * 6 + iIndexDO])
                    {
                        m_iSerialDataLen = formDatagram(2, iIndex + 1, iIndexDO, m_pIOModule->usDOCtrl[iIndex * 6 + iIndexDO]);
                        printSendInfo(m_pSerialDataBuf, m_iSerialDataLen);
                        if (m_iSerialDataLen >= 8)
                        {
                            if (m_iSerialDataLen == m_pSerial->writeBlock((unsigned char *)m_pSerialDataBuf, m_iSerialDataLen))
                            {
                                // Read from serial
                                readDataFromSerial();
                                printReceInfo(m_pSerialDataBuf, m_iSerialDataLen);

                                if (m_iSerialDataLen >= 6) // read OK
                                {
                                    analyDatagram(2, iIndex + 1, m_pSerialDataBuf, m_iSerialDataLen);
                                }
                            }
                        }
                    }
                }
            }

            // Read DO type = 3
            m_iSerialDataLen = formDatagram(3, iIndex + 1);
            printSendInfo(m_pSerialDataBuf, m_iSerialDataLen);
            if (m_iSerialDataLen >= 8)
            {
                if (m_iSerialDataLen == m_pSerial->writeBlock((unsigned char *)m_pSerialDataBuf, m_iSerialDataLen))
                {
                    // Read from serial
                    readDataFromSerial();
                    printReceInfo(m_pSerialDataBuf, m_iSerialDataLen);

                    if (m_iSerialDataLen >= 6) // read OK
                    {
                        int ret = analyDatagram(3, iIndex + 1, m_pSerialDataBuf, m_iSerialDataLen);
                        //printf("==================analyDatagram Read DO ret:%d\n", ret);
                    }
                }
            }
        }

        if (runCount <  5000)
        {
            runCount += 1;
            if (runCount <= 50)
                printf("========CIO runCount:%d\n", runCount);
        }


        //if (isFirstTimeRun) // added 2024-3-28
        if (10 == runCount)
        {
            //isFirstTimeRun = 0;
            for (int i = 0; i < 12; ++i)
            {
                m_pIOModule->usDOCtrl[i] = m_pIOModule->usDOState[i];
            }

            printf("******CIO read usDOCtrl1-12:%d-%d-%d-%d-%d-%d, %d-%d-%d-%d-%d-%d\n",
                   m_pIOModule->usDOCtrl[0],m_pIOModule->usDOCtrl[1],m_pIOModule->usDOCtrl[2],m_pIOModule->usDOCtrl[3],
                   m_pIOModule->usDOCtrl[4],m_pIOModule->usDOCtrl[5],m_pIOModule->usDOCtrl[6],m_pIOModule->usDOCtrl[7],
                   m_pIOModule->usDOCtrl[8],m_pIOModule->usDOCtrl[9],m_pIOModule->usDOCtrl[10],m_pIOModule->usDOCtrl[11]);
        }
    }
}

int CIO::prepareExcepDatagram(uchar uaExcepCode)
{
    int iIndex = 0;

    // Func Code
    iIndex = 1;
    *(m_pSerialDataBuf + iIndex) |= 0x80;
    iIndex += 1;

    // Err Code
    *(m_pSerialDataBuf + iIndex) = uaExcepCode;
    iIndex += 1;

    // CRC
    addModbusCRC2Buffer(m_pSerialDataBuf, iIndex);
    iIndex += 2;

    return iIndex;
}


int CIO::getParamFromBuffer(char* pData, quint16& uiParamVal)
{
    uiParamVal = (unsigned char)*pData;
    uiParamVal = uiParamVal * 256;

    ++pData;

    uiParamVal += (unsigned char)*pData;

    return 0;
}

int CIO::addParam2Buffer(char* pData, quint16 uiParamVal)
{
    *pData = (char)(uiParamVal >> 8);

    ++pData;
    *pData = (char)(uiParamVal);

    return  0;
}

// RTU
int CIO::addModbusCRC2Buffer(char *pData, int iLen)
{
    quint16 usCRC = Modbus_CRC16(pData, iLen);

    return addParam2Buffer(pData + iLen, usCRC);
}

//********************************************************************
// FUCTION: Modbus_CRC16 —— MODBUS RTU CRC16校验生成函数
// VERSION: 1	(2010-9-27 14:34:01)
// INPUT:	dat_buf 待校验数值缓存区
// 			dat_len 待校验数值缓存区的长度
// OUTPUT:	CRC16校验值
// EXAMPLE:
// 输入数据 dat_buf指向的数组为： 0x33, 0x78, 0x98, 0x60, 校验长度为4
// 则输出为：高字节0xE4 低字节0x91
//********************************************************************
quint16 CIO::Modbus_CRC16(char *dat_buf, quint16 usLen)  
{
    /* CRC 高位字节值表 */
    const uchar AUCHCRCHI[256]=
        {
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
            0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40
        };

    /* CRC 低位字节值表 */
    const uchar AUCHCRCLO[256]=
        {
            0,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,
            0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04,
            0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,
            0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8,
            0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,
            0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,
            0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,
            0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,
            0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,
            0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
            0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,
            0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,
            0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,
            0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,
            0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,
            0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,
            0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,
            0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,
            0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,
            0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
            0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,
            0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,
            0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,
            0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,
            0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,
            0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
            0x9c,0x5c,0x5d,0x9d,0x5f,0x9f,0x9e,0x5e,
            0x5a,0x9a,0x9b,0x5b,0x99,0x59,0x58,0x98,
            0x88,0x48,0x49,0x89,0x4b,0x8b,0x8a,0x4a,
            0x4e,0x8e,0x8f,0x4f,0x8d,0x4d,0x4c,0x8c,
            0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,
            0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40
        };

    uchar j,CH,CL;
    quint16 i;
    CH = 0XFF;
    CL = 0XFF;
    for (i = 0; i < usLen; i++)
    {
        j = dat_buf[i];
        j = CH ^ j;
        CH = CL ^ AUCHCRCHI[j];
        CL = AUCHCRCLO[j];
    }

    return(CH * 0x100 + CL);
}

